Il nuovo paesaggio dell'ottimizzazione CUDA rappresenta una rivoluzione concettuale dall'esecuzione tradizionale dei flussi limitata dal CPU all' ecosistema autonomo e accelerato a livello hardware. Questo passaggio riduce al minimo il carico sul lato host spostando direttamente nell'hardware GPU l'allocazione della memoria, la sincronizzazione e l'invio dei kernel.
1. Evoluzione dell'Interfaccia Software-Hardware
L'ottimizzazione inizia con il driver. Le applicazioni moderne utilizzano cuInit e cuModuleLoad per gestire i moduli. Una caratteristica chiave è Caricamento Lento (CUDA_MODULE_LOADING=LAZY), in cui le funzioni vengono caricate nel contesto GPU solo al primo invocazione, riducendo drasticamente l'utilizzo di memoria e il ritardo all'avvio.
2. Compatibilità Binaria e JIT
Le prestazioni sono mantenute tra diverse generazioni utilizzando PTX (Esecuzione in Parallelismo di Thread) e cubin. Il compilatore JIT si assicura che il PTX di alto livello sia ottimizzato per il Set di Funzionalità Specifiche dell'Architettura della GPU target all'esecuzione. Compilare contro CUDA 11.3, ad esempio, permette l'esecuzione su driver 11.4 senza ricompilazione grazie alla compatibilità ABI.
3. Limiti di Risorse ed Esecuzione
L'esecuzione moderna è governata da un mappaggio rigoroso delle risorse tra Buffer Parametri (PB) e Blocchi di Thread (TB). Questo viene espresso matematicamente come:
$$PB = \{BP_0, BP_1, \dots, BP_L\}, \quad TB = \{BT_0, BT_1, \dots, BT_L\}$$
Dove la validazione delle restrizioni hardware garantisce che $$BT_n \le BP_m$$ per $$n \le m$$. Questo framework permette lanci autonomi tramite cudaLaunchDevice rimanendo entro i limiti hardware.
4. Primitive Gestione Proattiva
L'ottimizzazione richiede ora una visibilità globale dei dati gestiti. Primitive come cudaMemPrefetchAsync e il Allocatore di Sistema permettono al GPU di preparare i dati prima dell'entrata nel kernel, eliminando i colli di bottiglia sincroni su piattaforme eterogenee con CPU Arm e GPU NVIDIA.